/*
 * Walker and TreeParser
 * Random Data Generator Language (RDGL)
 * by Navid Azimi, Summer 2007
 */

header {package rdgl.antlr;}
{
import java.util.*;
import rdgl.compiler.Engine;
import rdgl.compiler.Range;
import rdgl.compiler.Range.Type;
import rdgl.compiler.RandomData;
import rdgl.compiler.DataType;
}

class RDGLWalker extends TreeParser;

options {
    importVocab = RDGL;
}

{
	public void out(String line) {
		//System.out.println(line);
	}
}

program returns [ String result ]
{
	result = new String();
}
	: #(PROGRAM (prog:.
		{
			RandomData r = expr(#prog);
			result += r.getValue();
		})*)
	;

expr returns [ RandomData r ]
{
	r = new RandomData();
	Range i = null;
}
	: #(STATEMENT (smnt:.{ r.append(expr(#smnt).calculate()); })+)
	| #(LOOP i=modifier e:STATEMENT)
		{
			out("> LOOP");
			int value = Integer.parseInt(Engine.getRandomNumber(0, i.getSize() - 1));
			out("iters = " + i.get(value));
			for(int j = 0; j < Integer.parseInt(i.get(value)); j++) {
				RandomData temp = expr(e);
				out("TEMP: " + temp.toString());
				r.append(temp.getValue());
				out("R: " + r.toString());
			}
			out("< LOOP");
		}
	| #(POUND { r.setType(DataType.Number); r.calculate(); } (num:. {
			out("> POUND");
			r.setRange(modifier(#num));
			r.calculate();
			out("< POUND");
		})*)
	| #(AT { r.setType(DataType.Letter); r.calculate(); } (letter:. {
			out("> AT");
			r.setRange(modifier(#letter));
			r.calculate();
			out("< AT");
		})*)
	| #(AMPERSAND { r.setType(DataType.AlphaNumeric); r.calculate(); } (alphanumeric:. {
			out("> AMPERSAND");
			r.setRange(modifier(#alphanumeric));
			r.calculate();
			out("< AMPERSAND");
		})*)
	| #(DOLLAR { r.setType(DataType.Symbol); r.calculate(); } (symbol:. {
			out("> DOLLAR");
			r.setRange(modifier(#symbol));
			r.calculate();
			out("< DOLLAR");
		})*)
	| #(PERCENT { r.setType(DataType.Any); r.calculate(); } (wildcard:. {
			out("> PERCENT");
			r.setRange(modifier(#wildcard));
			r.calculate();
			out("< PERCENT");
		})*)
	| #(ENUMERATION { r.setType(DataType.Enum); r.calculate(); } (enu:. {
			out("> ENUMERATION");
			r.setRange(enumeration(#enu));
			r.calculate();
			out("< ENUMERATION");
		})*)
	;

modifier returns [ Range range ]
{
	range = new Range();
}
	: #(RANGE (rng:. {
			out("> RANGE");
			range = modifier(#rng);
			range.setType(Type.Range);
			out("< RANGE");
		})*)
	| #(LENGTH (len:. {
			out("> LENGTH");
			range = modifier(#len);
			range.setType(Type.Length);
			out("< LENGTH");
		})*)
	| #(VALUES_LIST (vals:. {
		out("> VALUES_LIST");
		range.add(values_list(#vals));
		out("< VALUES_LIST");
		})*)
	;

values_list returns [ List<String> values ]
{
	values = new ArrayList<String>();
	List<String> a, b;
}
	: num:NUMBER {
			out("> NUMBER");
			String number = num.getText();
			out("Number: " + number);
			values.add(number);
			out("< NUMBER");
		}
	| val:WORD {
			out("> WORD");
			String value = val.getText();
			out("Value: " + value);
			values.add(value);
			out("< WORD");
		}
	| #(MINUS a=values_list b=values_list) {
			int start = Integer.parseInt(a.get(0));
			int end = Integer.parseInt(b.get(0));
			
			if(start > end) {
				int temp = start;
				start = end;
				end = temp;
			}
			
			for(int i = start; i <= end; i++) {
				values.add(i + "");
			}
		}
	;

enumeration returns [ Range range ]
{
	range = new Range();
}
	: #(QUESTION (ques:. {
			out("> QUESTION");
			range.add(values_list(#ques));
			out("< QUESTION");
		})*)
	| #(ASTERISK (star:. {
			out("> ASTERISK");
			range.add(values_list(#star));
			// create an empty item in the list for nullable enumeration
			List<String> list = new ArrayList<String>();
			list.add("");
			range.add(list);	
			out("< ASTERISK");
		})*)
	;